﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Syngine.Components;
using Syngine.Components.Shapes;

namespace Syngine.Input.Mouse
{
	public class Marquee : DrawableGameComponent, IDraw//, IUpdate
	{
		#region Fields

		private static readonly Marquee Instance = new Marquee(Color.LightBlue);

		private readonly DrawableRectangle _rectangle;
		private Vector2 _position;
		private bool _startingToDrag;
		private Texture2D _filler;
		private Color _marqueeColor;

		#endregion

		#region Constructors

		static Marquee()
		{
			GameContext.Game.Components.Add(Instance);
		}

		private Marquee(Color color) : base(GameContext.Game)
		{
			_marqueeColor = color;
			_rectangle = new DrawableRectangle(Rectangle.Empty, _marqueeColor);

			Visible = true;
			Enabled = true;
			FillerAlpha = 0.15f;
		}

		#endregion

		#region Properties

		public bool Enabled { get; set; }

		public int DrawOrder { get; set; }

		public bool Visible { get; set; }

		public float FillerAlpha { get; set; }

		public bool IsDragging { get; private set; }

		public Rectangle Bounds
		{
			get
			{
				return _rectangle.Bounds;
			}
		}

		public Color Color
		{
			get
			{
				return _marqueeColor;
			}
			set
			{
				_marqueeColor = value;

				if (_filler != null)
				{
					UpdateColor();
				}
			}
		}

		#endregion

		#region Methods

		public static MarqueeState GetState()
		{
			return new MarqueeState(Instance.Bounds, Instance.IsDragging);
		}

		void ILoad.UnloadContent()
		{
		}

		public bool IsInitialized { get; private set; }

		public override void Initialize()
		{
			_rectangle.Initialize();

			var input = GameContext.Input;
			input.If(i => i.IsDown(MouseButtons.Left)).Call(MouseDraggingCallback);
			input.If(i => i.WasReleased(MouseButtons.Left)).Call(i =>
			{
				IsDragging = false;
				_startingToDrag = false;
				_rectangle.Bounds = Rectangle.Empty;
			});

			IsInitialized = true;

			base.Initialize();
		}

		protected override void LoadContent()
		{
			LoadContent(GameContext.CreateLoadContext());
			base.LoadContent();
		}

		public void LoadContent(LoadContext context)
		{
			_filler = new Texture2D(context.GraphicsDevice, 1, 1);

			UpdateColor();

			base.LoadContent();
		}

		//public void Update(UpdateContext context)
		//{
		//}

		public override void Draw(GameTime gameTime)
		{
			if (Visible && Enabled)
			{
				if (IsDragging)
				{
					Draw(GameContext.CreateDrawContext(gameTime, true));
				}
			}

			base.Draw(gameTime);
		}

		public void Draw(DrawContext context)
		{
			context.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
			context.Draw(_filler, Bounds, _marqueeColor);
			context.End();

			_rectangle.Draw(context);
		}

		public bool Contains(Vector2 vector)
		{
			return Contains(vector.X, vector.Y);
		}

		public bool Contains(Point point)
		{
			return Contains(point.X, point.Y);
		}

		public bool Contains(float x, float y)
		{
			return Contains((int) x, (int) y);
		}

		public bool Contains(int x, int y)
		{
			return (IsDragging && Bounds.Contains(x, y));
		}

		private void MouseDraggingCallback(InputCallbackContext input)
		{
			if (Enabled)
			{
				if (!_startingToDrag)
				{
					_position = input.Current.MouseState.Position();
					_startingToDrag = true;
				}

				if (_startingToDrag && !IsDragging)
				{
					var mousePosition = input.Current.MouseState.Position();
					var startPosition = new Vector2(_position.X, _position.Y);

					if (Vector2.Distance(startPosition, mousePosition) >= 4.0f)
					{
						IsDragging = true;
					}
				}

				if (IsDragging)
				{
					var start = new Vector2();
					var dimensions = new Vector2();
					var state = input.Current.MouseState;

					if (_position.X > state.X)
					{
						start.X = state.X;
						dimensions.X = _position.X - start.X;
					}
					else
					{
						start.X = _position.X;
						dimensions.X = state.X - start.X;
					}

					if (_position.Y > state.Y)
					{
						start.Y = state.Y;
						dimensions.Y = _position.Y - start.Y;
					}
					else
					{
						start.Y = _position.Y;
						dimensions.Y = state.Y - start.Y;
					}

					_rectangle.Bounds = new Rectangle((int)start.X, (int)start.Y, (int)dimensions.X, (int)dimensions.Y);
				}
			}
			else
			{
				_startingToDrag = false;
				IsDragging = false;
			}
		}

		private void UpdateColor()
		{
			_filler.SetData(new [] {new Color(_marqueeColor.R, _marqueeColor.G, _marqueeColor.B, FillerAlpha)});
		}

		#endregion
	}
}